/*
 * // +-------------------------------------------------------------------------------------------------
 * // |                 有你就好 [ 有节骨乃坚，无心品自端 ]     <http://encoding.wang>
 * // +-------------------------------------------------------------------------------------------------
 * // |                             独在异乡为异客         每逢佳节倍思亲
 * // +-------------------------------------------------------------------------------------------------
 * // |                 联系:   <707069100@qq.com>      <http://weibo.com/513778937>
 * // +-------------------------------------------------------------------------------------------------
 */

// -----------------------------------------------------------------------------------------------------
// +----------------------------------------------------------------------------------------------------
// |                   ErYang出品 属于小极品          共同学习    共同进步
// +----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------


package wang.encoding.mroot.common.interceptor


import com.alibaba.fastjson.JSONObject
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
import org.springframework.web.method.HandlerMethod
import org.springframework.web.servlet.HandlerInterceptor
import org.springframework.web.servlet.ModelAndView
import wang.encoding.mroot.common.annotation.FormToken
import wang.encoding.mroot.common.business.ResultData
import wang.encoding.mroot.common.config.LocaleMessageSourceConfiguration
import wang.encoding.mroot.common.constant.ShareConst
import wang.encoding.mroot.common.exception.BaseException
import wang.encoding.mroot.common.util.HttpRequestUtil
import java.io.IOException
import java.io.PrintWriter
import java.lang.reflect.Method
import java.util.*
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import javax.servlet.http.HttpSession


/**
 * 防止表单重复提交拦截器
 *
 * @author ErYang
 */
@Component
class FormTokenInterceptor : HandlerInterceptor {

    companion object {

        private val logger: Logger = LoggerFactory.getLogger(FormTokenInterceptor::class.java)

        /**
         * 错误页面地址
         */
        private const val ERROR404_URL: String = "/error/404"

    }

    @Value(value = "\${server.servlet.contextPath}")
    protected lateinit var contextPath: String

    @Autowired
    private lateinit var shareProperties: ShareConst

    @Autowired
    protected lateinit var httpRequestUtil: HttpRequestUtil

    @Autowired
    protected lateinit var localeMessageSourceConfiguration: LocaleMessageSourceConfiguration

    @Throws(BaseException::class)
    override fun preHandle(httpServletRequest: HttpServletRequest,
                           httpServletResponse: HttpServletResponse, o: Any): Boolean {
        if (logger.isDebugEnabled) {
            logger.debug(">>>>>>>>FormTokenInterceptor[${httpServletRequest.requestURI}]<<<<<<<<")
        }
        if (o is HandlerMethod) {
            val handlerMethod: HandlerMethod? = o
            val method: Method = handlerMethod!!.method
            // 得到注解
            val annotation: FormToken? = method.getAnnotation(FormToken::class.java)
            if (null != annotation) {
                // 需要防止重复提交
                val needSaveSession: Boolean = annotation.init
                // 生成 token
                if (needSaveSession) {
                    val tokenValue: String = UUID.randomUUID().toString()
                    httpServletRequest.getSession(true).setAttribute(shareProperties.formToken, tokenValue)
                    return true
                }
                // 验证 token
                val needRemoveSession: Boolean = annotation.remove
                if (needRemoveSession) {
                    // 判断是否是重复提交
                    if (this.isRepeatSubmit(httpServletRequest)) {
                        // ajax 请求
                        if (httpRequestUtil.isAjaxRequest(httpServletRequest)) {

                            // 新的 token
                            val tokenValue: String = UUID.randomUUID().toString()
                            httpServletRequest.getSession(true).setAttribute(shareProperties.formToken,
                                    tokenValue)

                            val result: ResultData = ResultData.repeat()
                            result.setRepeat()["message"] = localeMessageSourceConfiguration
                                    .getMessage("message.repeat.info")
                            result.setRepeat()["formToken"] = tokenValue
                            this.returnJson(httpServletResponse, result.toFastJson())
                        } else {
                            // 非法请求 重定向到异常页面
                            val url: String? = httpServletRequest.getHeader("Referer")
                            if (null != url && url.isNotBlank()) {
                                httpServletResponse.sendRedirect(url)
                            } else {
                                httpServletResponse.sendRedirect(contextPath + ERROR404_URL)
                            }
                        }
                        return false
                    } else {
                        httpServletRequest.getSession(true).removeAttribute(shareProperties.formToken)
                    }
                }
            }
        }
        return true
    }

    // -------------------------------------------------------------------------------------------------

    @Throws(BaseException::class)
    override fun postHandle(httpServletRequest: HttpServletRequest,
                            httpServletResponse: HttpServletResponse,
                            o: Any, modelAndView: ModelAndView?) {

    }

    // -------------------------------------------------------------------------------------------------

    @Throws(BaseException::class)
    override fun afterCompletion(httpServletRequest: HttpServletRequest,
                                 httpServletResponse: HttpServletResponse,
                                 o: Any, e: Exception?) {

    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 判断是否是重复提交
     *
     * @param request request
     * @return true(重复提交)/false(否)
     */
    private fun isRepeatSubmit(request: HttpServletRequest): Boolean {
        val session: HttpSession = request.getSession(true)
        session.getAttribute(shareProperties.formToken) ?: return true
        val serverToken: String = session.getAttribute(shareProperties.formToken) as String
        val clientToken: String? = request.getParameter(shareProperties.formToken) ?: return true
        return serverToken != clientToken
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 打印json数据
     *
     * @param response response
     * @param json     json
     * @throws Exception
     */
    @Throws(BaseException::class)
    private fun returnJson(response: HttpServletResponse, json: JSONObject) {
        var writer: PrintWriter? = null
        response.characterEncoding = "UTF-8"
        response.contentType = "text/html;charset=utf-8"
        try {
            writer = response.writer
            writer!!.print(json)
        } catch (e: IOException) {
            if (logger.isErrorEnabled) {
                logger.error(localeMessageSourceConfiguration.getMessage("message.error"), e)
            }
        } finally {
            if (writer != null)
                writer.close()
        }
    }

    // -------------------------------------------------------------------------------------------------

}

// -----------------------------------------------------------------------------------------------------

// End FormTokenInterceptor class

/* End of file FormTokenInterceptor.kt */
/* Location: ./src/main/kotlin/wang/encoding/mroot/common/interceptor/FormTokenInterceptor.kt */

// -----------------------------------------------------------------------------------------------------
// +----------------------------------------------------------------------------------------------------
// |                           ErYang出品 属于小极品  O(∩_∩)O~~   共同学习    共同进步
// +----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------
